package com.jxb.test20241021;

import java.util.LinkedList;
import java.util.Random;

/**
 * 滑动窗口算法
 * 设置滑动窗口：1s，每个格子200ms，一共5个槽位
 * 逻辑：
 *  1：编写限流监测方法
 *      1：设置一个死循环，每次执行延时200ms
 *      2：执行详细步骤如下：
 *          a：将计数器中的值设置到槽位中
 *          b：判断槽位数量是否大于设定的值，大于，移除第一位
 *          c：小于，判断滑动窗口中的总流量是否大于qps，大于，则将限流标识设置为true，否则设置为false
 *  2：模拟高并发
 */
public class SlidingTimeWindow1 {

    private static LinkedList<Long> slidingTimeWin = new LinkedList<>();//存储滑动时间窗

    private static Long limit = 20L;

    private static Long size = 5L;

    private static Long counter = 0L;//计数器

    private static boolean isLimit;//限流标记

    public static void main(String[] args) throws InterruptedException {
        //启动限流监测
        new Thread(new Runnable() {
            @Override
            public void run() {
                doCheck();
            }
        }).start();

        //模拟高并发
        while (true) {
            if (isLimit) {
                System.out.println("限流了.............");
            }else {
                System.out.println("正常执行");
                counter++;
            }
            Thread.sleep(new Random().nextInt(15));
        }
    }

    public static void doCheck() {
        while(true) {
            slidingTimeWin.addLast(counter);
            //判断时间窗是否需要滑动
            if (slidingTimeWin.size() > size) {
                slidingTimeWin.remove();
            }
            Long total = slidingTimeWin.peekLast() - slidingTimeWin.peekFirst();
            if (total > limit) {
                //修改限流标记为true，进行限流
                isLimit = true;
            }else {
                //修改限流标记为false
                isLimit = false;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
